package com.niiwoo.civet.trade.service.local.loan.composite;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.trade.dao.entity.LoanBusinessConfig;
import com.niiwoo.civet.trade.dao.entity.Project;
import com.niiwoo.civet.trade.dao.mapper.ProjectMapperExt;
import com.niiwoo.civet.trade.dto.request.ProjectFlowRequestDTO;
import com.niiwoo.civet.trade.enums.LoanSubmitTypeEnum;
import com.niiwoo.civet.trade.enums.ProjectSubStatusEnum;
import com.niiwoo.civet.trade.enums.ProjectTypeEnum;
import com.niiwoo.civet.trade.enums.TradeConfigEnum;
import com.niiwoo.civet.trade.service.local.configure.TradeConfigLocalService;
import com.niiwoo.civet.trade.service.local.loan.LoanConfigService;
import com.niiwoo.civet.trade.service.local.project.ProjectLocalService;
import com.niiwoo.civet.user.dto.request.AddUserLoanLimitRequestDTO;
import com.niiwoo.civet.user.enums.LibraLoanLimitEnum;
import com.niiwoo.civet.user.enums.ProductTypeEnum;
import com.niiwoo.civet.user.service.UserForbidDubboService;
import com.niiwoo.tripod.provider.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.FastDateFormat;
import org.joda.time.DateTime;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.function.Function;

/**
 * @Author: wuke
 * @Description:
 * @Date: Created in 13:57 2018/5/15
 */
@Slf4j
@Service
public class LoanService {
    @Autowired
    private ProjectMapperExt projectMapper;
    @Autowired
    protected LoanConfigService loanConfigService;
    @Autowired
    private ProjectLocalService projectLocalService;
    @Autowired
    protected TradeConfigLocalService tradeConfigLocalService;
    @Reference(version = "1.0.0")
    protected UserForbidDubboService userForbidDubboService;

    public void returnConfirmOverTimeBatchProcess(){
        confirmOverTimeBatchProcess(
                LoanBusinessConfig::getReturnConfirmMaxDays,
                (overDate->doReturnConfirmOverTimeBatchProcess(overDate))
        );
    }

    public void passConfirmOverTimeBatchProcess(){
        confirmOverTimeBatchProcess(
                LoanBusinessConfig::getPassConfirmMaxDays,
                (overDate->doPassConfirmOverTimeBatchProcess(overDate))
        );
    }


    private void confirmOverTimeBatchProcess(Function<LoanBusinessConfig,Short> confirmMaxDaysFunc, Function<Date,Boolean> doConfirmOverTimeBatchProcessFunc){
        LoanBusinessConfig loanBusinessConfig = loanConfigService.selectBusinessConfig(getProjectType());

        log.info("confirmOverTimeBatchProcess.loanBusinessConfig={}", JSON.toJSONString(loanBusinessConfig));

        if(loanBusinessConfig==null){
            return;
        }

        Short confirmMaxDays = confirmMaxDaysFunc.apply(loanBusinessConfig);

        log.info("confirmOverTimeBatchProcess.confirmMaxDays={}", confirmMaxDays);

        if(confirmMaxDays==null){
            return;
        }

        Date overDate = getOverDate(confirmMaxDays);

        int times = 0;
        boolean isNotEnd = false;
        do {
            isNotEnd = doConfirmOverTimeBatchProcessFunc.apply(overDate);
            times += 1;
        }while (isNotEnd && times<300);
    }

    private boolean doReturnConfirmOverTimeBatchProcess(Date overDate){
        //获取超时未确认的所有退表标的数据
        List<Project> returnOverTimeList = getReturnConfirmOverTimeList(overDate);

        log.info("doReturnConfirmOverTimeBatchProcess.returnOverTimeList={}",returnOverTimeList);

        if(CollectionUtils.isEmpty(returnOverTimeList)){
            return false;
        }

        returnOverTimeList.forEach(project -> {
            doReturnConfirmOverTimeProcess(project.getBorrowUserId(),project.getProjectId());
        });

        return true;
    }

    private boolean doPassConfirmOverTimeBatchProcess(Date overDate){
        //获取超时未确认的所有退表标的数据
        List<Project> passConfirmOverTimeList = getPassConfirmOverTimeList(overDate);

        log.info("doPassConfirmOverTimeBatchProcess.returnOverTimeList={}",passConfirmOverTimeList);

        if(CollectionUtils.isEmpty(passConfirmOverTimeList)){
            return false;
        }

        passConfirmOverTimeList.forEach(project -> {
            doPassConfirmOverTimeProcess(project.getBorrowUserId(),project.getProjectId());
        });

        return true;
    }

    private Date getOverDate(int limitDays){
        log.info("getOverDate.limitDays={}", limitDays);
        try {
            FastDateFormat fastDateFormat = FastDateFormat.getInstance("yyyy-MM-dd");
            Date overDate = fastDateFormat.parse(fastDateFormat.format(DateTime.now().plusDays(-limitDays).toDate()));
            log.info("getOverDate.overDate={}", overDate);
            return overDate;
        } catch (ParseException e) {
            log.error("getOverDate异常,limitDays={}",limitDays,e);
            return null;
        }
    }

    @Transactional
    public List<Project> getOverTimeList(Date overDate,List<ProjectSubStatusEnum> subStatusEnumList){
        if(overDate==null){
            return null;
        }
        ProjectTypeEnum projectType = getProjectType();

        log.info("getOverTimeList.projectType={}", JSON.toJSONString(projectType));

        return projectMapper.selectListByOverDate(projectType, subStatusEnumList,overDate);
    }

    public List<Project> getReturnConfirmOverTimeList(Date overDate){

        List<Project> overTimeList = getSelfProxy().getOverTimeList(overDate, Arrays.asList(
                ProjectSubStatusEnum.CHECKING_BACK,
                ProjectSubStatusEnum.CHECKING_BACK_PHONEOPERATOR_TIMEOUT,
                ProjectSubStatusEnum.CHECKING_BACK_ADDRESSLIST_TIMEOUT));

        return overTimeList;
    }

    public List<Project> getPassConfirmOverTimeList(Date overDate){
        List<Project> overTimeList = getOverTimeList(overDate, Arrays.asList(ProjectSubStatusEnum.CHECKING_FOR_CONFIRM));

        return overTimeList;
    }

    public void doPassConfirmOverTimeProcess(String userId, Long projectId){
        log.info("doPassConfirmOverTimeProcess.userId={},projectId={} start",userId,projectId);
        try {
            //流标
            getSelfProxy().flow(
                    projectId,
                    ProjectSubStatusEnum.MISCARRY_CONFIRMED_OVERTIME,
                    Arrays.asList(ProjectSubStatusEnum.CHECKING_FOR_CONFIRM)
            );

            //添加借款限制
            addUserLibraLoanLimit(userId,getProjectType().getValue());
        } catch (Exception e) {
            log.error("doPassConfirmOverTimeProcess.userId={},projectId={}",userId,projectId,e);
        }
    }

    public void doReturnConfirmOverTimeProcess(String userId, Long projectId){
        log.info("doReturnConfirmOverTimeProcess.userId={},projectId={} start",userId,projectId);
        try {
            //流标
            getSelfProxy().flow(
                    projectId,
                    ProjectSubStatusEnum.MISCARRY_BACK_OVERTIME,
                    Arrays.asList(
                            ProjectSubStatusEnum.CHECKING_BACK,
                            ProjectSubStatusEnum.CHECKING_BACK_PHONEOPERATOR_TIMEOUT,
                            ProjectSubStatusEnum.CHECKING_BACK_ADDRESSLIST_TIMEOUT
                    )
            );

            //添加借款限制
            addUserLibraLoanLimitAllType(userId);
        } catch (Exception e) {
            log.error("doReturnConfirmOverTimeProcess.userId={},projectId={}异常",userId,projectId,e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void flow(Long projectId,ProjectSubStatusEnum flowSubStatusEnum,List<ProjectSubStatusEnum> origSubStatusEnumList){
        //标的子状态检查
        projectSubStatusCheck(projectId,origSubStatusEnumList);

        ProjectFlowRequestDTO requestDTO=new ProjectFlowRequestDTO();
        requestDTO.setProjectId(projectId);
        requestDTO.setSubStatus(flowSubStatusEnum);
        projectLocalService.flow(requestDTO);
    }

    //标的子状态检查
    @Transactional(rollbackFor = Exception.class)
    public void projectSubStatusCheck(Long projectId,List<ProjectSubStatusEnum> origSubStatusEnumList){
        Project project = projectMapper.selectByPrimaryKeyForUpdate(projectId);
        Integer subStatus = project.getSubStatus();
        for(ProjectSubStatusEnum origSubStatusEnum:origSubStatusEnumList){
            if(origSubStatusEnum.getSubStatus()==subStatus.intValue()){
                return;
            }
        }
        throw new BizException("TRD1000008");
    }

    //添加借款限制
    public void addUserLibraLoanLimitAllType(String userId){
        AddUserLoanLimitRequestDTO addUserLoanLimitRequestDTO = new AddUserLoanLimitRequestDTO();
        addUserLoanLimitRequestDTO.setUserId(userId);
        addUserLoanLimitRequestDTO.setLimitType(LibraLoanLimitEnum.USER_CONFIRM_OVERTIME.getLimitType().intValue());
        String limitDays = getTradeConfigValue(TradeConfigEnum.ARTIFICIALRETURNANDNOTREBORROWLIMIT,"7");
        addUserLoanLimitRequestDTO.setLimitDays(Integer.valueOf(limitDays));
        userForbidDubboService.addUserLibraLoanLimitAllType(addUserLoanLimitRequestDTO);
    }

    //添加借款限制
    public void addUserLibraLoanLimit(String userId, Byte productType){
        AddUserLoanLimitRequestDTO addUserLoanLimitRequestDTO = new AddUserLoanLimitRequestDTO();
        addUserLoanLimitRequestDTO.setUserId(userId);
        addUserLoanLimitRequestDTO.setProductTypeEnum(ProductTypeEnum.enumOf(productType));
        addUserLoanLimitRequestDTO.setLimitType(LibraLoanLimitEnum.USER_CONFIRM_OVERTIME.getLimitType().intValue());
        String limitDays = getTradeConfigValue(TradeConfigEnum.WAITCONFIRMANDNOTREBORROWLIMIT,"7");
        addUserLoanLimitRequestDTO.setLimitDays(Integer.valueOf(limitDays));
        userForbidDubboService.addUserLibraLoanLimit(addUserLoanLimitRequestDTO);
    }

    protected String getTradeConfigValue(TradeConfigEnum configEnum, String defaultValue){
        String result = defaultValue;
        try {
            String value = tradeConfigLocalService.selectTradeConfigByEmun(configEnum);
            result = (StringUtils.hasText(value)?value:result);
        } catch (Exception e) {
            log.error("getTradeConfigValue异常，configEnum={}",JSON.toJSONString(configEnum),e);
        }
        return result;
    }

    protected ProjectTypeEnum getProjectType(){
        return getLoanSubmitMapEnum().getProjectTypeEnum();
    }

    protected LoanSubmitTypeEnum getLoanSubmitMapEnum(){return null;};

    public void setUserForbidDubboService(UserForbidDubboService userForbidDubboService) {
        this.userForbidDubboService = userForbidDubboService;
    }

    protected LoanService getSelfProxy(){
        return (LoanService) AopContext.currentProxy();
    }
}
